#!/usr/bin/env python
#
# Routines for reading simulator grid map files produced by the
# map_format_writer input module.
#
# Author:   Mike Murphy <mamurph@cs.clemson.edu>
# Revision: 23 September 2009
#
#   Copyright 2009 Clemson University
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
#
# This material is based upon work supported under a National Science
# Foundation Graduate Research Fellowship. Any opinions, findings,
# conclusions or recommendations expressed in this publication are those of
# the author(s) and do not necessarily reflect the views of the National
# Science Foundation.

'''
Reader mechanism for dynamic grid map files produced by the map_format_writer
input module.
'''

from common_reader import CommonReader
from results import SiteResult

MAP_FORMAT = 0.90


class MapReader(CommonReader):
   '''
   Reader for dynamic grid map files, the textual format of which is
   documented externally. Reader instances are simulator-aware and parse
   the map file as needed by the simulator.
   '''
   def __init__(self, filename, fh, simobj, grid):
      '''
      @param filename: Name of open grid map file
      @type filename: str
      @param fh: Handle to open grid map file (r mode)
      @param simobj: Simulator object reference
      @param grid: Grid object whose resize_cluster, add_ce, and remove_ce
                   methods will be called in response to map commands
      '''
      prefix = 'mapmeta_' + filename + '_'
      CommonReader.__init__(self, filename, fh, simobj, MAP_FORMAT, prefix)
      self.grid = grid
      self.add_handler('grow', self.h_cluster)
      self.add_handler('shrink', self.h_cluster)
      self.add_handler('add', self.h_add)
      self.add_handler('del', self.h_del)
   def h_cluster(self):
      '''
      Parse handler for the grow and shrink commands.

      @rtype: bool
      @return: True'''
      if len(self.parts) not in (3, 4):
         self.error('%s command takes 2 or 3 arguments' % self.parts[0])
      try:
         cluster = self.parts[1]
         count = int(self.parts[2])
         if self.parts[0] == 'shrink':
            count *= -1
         profile = ''
         if len(self.parts) == 4:
            profile = self.parts[3]
         self.grid.resize_cluster(cluster, count, profile)
      except Exception, msg:
         self.error(msg)
      return True
   def h_add(self):
      '''
      Parse handler for the add command.

      @rtype: bool
      @return: True
      '''
      if len(self.parts) != 4:
         self.error('add command takes exactly 3 arguments')
      try:
         site_name = self.parts[1]
         cluster_name = self.parts[2]
         sched_name = self.parts[3]
         site = self.grid.add_ce(site_name, cluster_name, sched_name)
         r = SiteResult(self.sim.get_timestamp(), site_name, sched_name, \
                        cluster_name, site.get_cpu_count())
         self.sim.add_result(r)
      except Exception, msg:
         self.error(msg)
      return True
   def h_del(self):
      '''
      Parse handler for the del command.

      @rtype: bool
      @return: True
      '''
      if len(self.parts) != 2:
         self.error('del command takes exactly 1 argument')
      try:
         site_name = self.parts[1]
         site = self.grid.remove_ce(site_name)
         r = SiteResult(self.sim.get_timestamp(), site_name, \
                        site.sched.name, site.cluster.name, \
                        -1*site.get_cpu_count())
      except Exception, msg:
         self.error(msg)
      return True
#
